package server

import (
	"bs/logger"
	"bs/response"
	"bs/sql"

	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
	"github.com/xuri/excelize/v2"
	"golang.org/x/crypto/bcrypt"
)

// 定义一个密钥，用于签名 JWT
var jwtKey = []byte("123456")

// GenerateToken 生成 JWT
func GenerateToken(username string) (string, error) {
	// 创建声明
	claims := &jwt.StandardClaims{
		ExpiresAt: time.Now().Add(time.Hour * 72).Unix(), // 过期时间为72小时
		Issuer:    username,
	}

	// 创建 token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 使用密钥签名 token
	signedToken, err := token.SignedString(jwtKey)
	if err != nil {
		return "", err
	}
	return signedToken, nil
}

// 登录
func Login(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}

	//请求数据库获取用户信息
	user, err := db.GetUserByUsername(req.Username)
	if err != nil {
		logger.Logger.Error("Error getting user: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("获取用户信息失败").SetCode(500))
		return
	}
	//检查密码是否正确
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		logger.Logger.Error("Invalid password: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("密码错误").SetCode(401))
		return
	}
	//生成token
	token, err := GenerateToken(user.Name)
	if err != nil {
		logger.Logger.Error("Error generating token: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("生成token失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, map[string]any{
		"token":   token,
		"role":    user.Role,
		"usrname": user.Username,
	})

}

func GetEvents(c *gin.Context, db *sql.DB) {
    resp := response.NewFailResp()

    // 从查询参数中获取分页信息
    page, err := strconv.Atoi(c.Query("page"))
    if err != nil {
        logger.Logger.Error("Invalid page parameter: ", err)
        response.WriteFailedResp(c, *resp.SetMsg("无效的页码").SetCode(400))
        return
    }

    pageSize, err := strconv.Atoi(c.Query("pageSize"))
    if err != nil {
        logger.Logger.Error("Invalid pageSize parameter: ", err)
        response.WriteFailedResp(c, *resp.SetMsg("无效的页面大小").SetCode(400))
        return
    }

    // 请求数据库获取赛事列表
    events, total, err := db.GetEvents(page, pageSize)
    if err != nil {
        logger.Logger.Error("Error getting events: ", err)
        response.WriteFailedResp(c, *resp.SetMsg("获取赛事列表失败").SetCode(500))
        return
    }

    response.WriteOKResp(c, map[string]interface{}{
        "list":  events,
        "total": total,
    })
}

// 自定义时间类型（兼容前端格式）
type DateTime struct {
	time.Time
}

// 实现 UnmarshalJSON 方法
func (dt *DateTime) UnmarshalJSON(b []byte) error {
	s := strings.Trim(string(b), `"`)

	// 尝试解析两种格式
	t, err := time.Parse("2006-01-02 15:04:05", s)
	if err != nil {
		t, err = time.Parse(time.RFC3339, s)
		if err != nil {
			return fmt.Errorf("无效时间格式，需要格式：2006-01-02 15:04:05 或 RFC3339")
		}
	}

	dt.Time = t
	return nil
}

// 录入赛事
func CreateEvents(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Name      string    `json:"name"`
		StartTime DateTime `json:"startTime"`
		EndTime   DateTime `json:"endTime"`
		Rules     string    `json:"rules"`
	}
	var req request

	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}

	event := &sql.Event{
		Name:      req.Name,
		StartTime: req.StartTime.Time,
		EndTime:   req.EndTime.Time,
		Rules:     req.Rules,
	}
	if err := db.CreateEvent(event); err != nil {
		logger.Logger.Error("Error creating event: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("创建赛事失败").SetCode(500))
		return
	}

	response.WriteOKResp(c, map[string]any{
		"id": event.ID,
	})
}

// 修改赛事(put)
func UpdateEvent(c *gin.Context, db *sql.DB) {
    resp := response.NewFailResp()
    
    //获取并验证路径参数
    idStr := c.Param("id")
    eventID, err := strconv.Atoi(idStr)
    if err != nil || eventID <= 0 {
        logger.Logger.Error("Invalid event ID: " + idStr)
        response.WriteFailedResp(c, *resp.SetMsg("无效的赛事ID").SetCode(400))
        return
    }

    //解析请求体
    type request struct {
        Name      string    `json:"name"`
        StartTime DateTime `json:"startTime"`
        EndTime   DateTime `json:"endTime"`
        Rules     string    `json:"rules"`
    }
    
    var req request
    if err := c.ShouldBindJSON(&req); err != nil {
        logger.Logger.Error("Invalid request format: ", err)
        response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
        return
    }

    // 3. 业务逻辑验证
    if req.StartTime.After(req.EndTime.Time) {
        response.WriteFailedResp(c, *resp.SetMsg("开始时间不能晚于结束时间").SetCode(400))
        return
    }

    // 4. 构建更新对象
    event := &sql.Event{
        Name:      req.Name,
        StartTime: req.StartTime.Time,
        EndTime:   req.EndTime.Time,
        Rules:     req.Rules,
    }

    // 5. 数据库操作
    if err := db.UpdateEvent(event,eventID); err != nil {
        logger.Logger.Error("Error updating event: ", err)
        response.WriteFailedResp(c, *resp.SetMsg("修改赛事失败").SetCode(500))
        return
    }


    response.WriteOKResp(c, nil)
}

// 查看所有报名
func GetResgistration(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Page     int `json:"page"`
		PageSize int `json:"pageSize"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	registrations, total, err := db.GetRegistrations(req.Page, req.PageSize)
	if err != nil {
		logger.Logger.Error("Error getting registrations: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("获取报名列表失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, map[string]any{
		"list":  registrations,
		"total": total,
	})
}

// 新增报名
func CreateRegistration(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		EventID uint   `json:"eventID"`
		Name    string `json:"name"`
		Age     int    `json:"age"`
		Gender  string `json:"gender"`
		Group   string `json:"group"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	registration := &sql.Registration{
		EventID: req.EventID,
		Name:    req.Name,
		Age:     req.Age,
		Gender:  req.Gender,
		Group:   req.Group,
	}
	if err := db.CreateRegistration(registration); err != nil {
		logger.Logger.Error("Error creating registration: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("创建报名失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

// 生成成绩册并返回 Excel 文件
func GenerateResult(c *gin.Context, db *sql.DB) {
	// 直接调用数据库查询 results 表
	results, err := db.GetResults()
	if err != nil {
		logger.Logger.Error("Error getting results: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("获取成绩册失败").SetCode(500))
		return
	}

	// 创建一个新的 Excel 文件
	file := xlsx.NewFile()
	sheet, err := file.AddSheet("Results")
	if err != nil {
		logger.Logger.Error("Error creating sheet: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("创建 Excel 表格失败").SetCode(500))
		return
	}

	// 添加表头
	header := sheet.AddRow()
	header.AddCell().Value = "ID"
	header.AddCell().Value = "Event ID"
	header.AddCell().Value = "Registration ID"
	header.AddCell().Value = "Score"
	header.AddCell().Value = "Created At"

	// 填充数据
	for _, result := range results {
		row := sheet.AddRow()
		row.AddCell().Value = strconv.Itoa(int(result.ID))
		row.AddCell().Value = strconv.Itoa(int(result.EventID))
		row.AddCell().Value = strconv.Itoa(int(result.RegistrationID))
		row.AddCell().Value = result.Score
		row.AddCell().Value = result.CreatedAt.Format("2006-01-02 15:04:05")
	}

	// 设置文件类型和名称
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Header("Content-Disposition", "attachment; filename=results.xlsx")

	// 将文件写入响应
	if err := file.Write(c.Writer); err != nil {
		logger.Logger.Error("Error writing Excel file: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("写入 Excel 文件失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

// 查看所有成绩
func GetResult(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Page     int `json:"page"`
		PageSize int `json:"pageSize"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	results, total, err := db.GetResult(req.Page, req.PageSize)
	if err != nil {
		logger.Logger.Error("Error getting results: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("获取成绩失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, map[string]any{
		"list":  results,
		"total": total,
	})
}

// 录入成绩
func CreateResult(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		EventID uint   `json:"eventID"`
		Name    string `json:"name"`
		Score   string `json:"score"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	err := db.CreateResult(req.Name, req.Score, req.EventID)
	if err != nil {
		logger.Logger.Error("Error creating result: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("创建成绩失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

// 查看所有用户
func GetUsers(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Page     int `json:"page"`
		PageSize int `json:"pageSize"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	users, total, err := db.GetUsers(req.Page, req.PageSize)
	if err != nil {
		logger.Logger.Error("Error getting users: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("获取用户失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, map[string]any{
		"list":  users,
		"total": total,
	})
}

// 新增用户
func CreateUser(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Username string `json:"username"`
		Password string `json:"password"`
		Role     string `json:"role"`
		Name     string `json:"name"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	//检查用户名是否已存在
	ifuser, _ := db.GetUserByUsername(req.Username)
	if ifuser != nil {
		response.WriteFailedResp(c, *resp.SetMsg("用户名已存在").SetCode(400))
		return
	}

	//哈希加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		response.WriteResp(c, *resp.SetMsg("Error registering user"))
		return
	}

	user := &sql.User{
		Username: req.Username,
		Password: string(hashedPassword),
		Role:     req.Role,
		Name:     req.Name,
	}
	if err := db.CreateUser(user); err != nil {
		logger.Logger.Error("Error creating user: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("创建用户失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

// 修改用户
func UpdateUser(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		Name string `json:"name"`
		Role string `json:"role"`
	}

	//路径参数
	idStr := c.Param("id")
	id, err := strconv.Atoi(idStr)
	if err!= nil || id <= 0 {
		logger.Logger.Error("Invalid user ID: " + idStr)
		response.WriteFailedResp(c, *resp.SetMsg("无效的用户ID").SetCode(400))
		return
	}

	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}

	if err := db.UpdateUser(req.Name,req.Role,id); err != nil {
		logger.Logger.Error("Error updating user: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("修改用户失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

// 删除用户
func DeleteUser(c *gin.Context, db *sql.DB) {
	resp := response.NewFailResp()
	type request struct {
		ID uint `json:"id"`
	}
	var req request
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.Logger.Error("Invalid request format: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("无效的请求格式").SetCode(400))
		return
	}
	if err := db.DeleteUser(req.ID); err != nil {
		logger.Logger.Error("Error deleting user: ", err)
		response.WriteFailedResp(c, *resp.SetMsg("删除用户失败").SetCode(500))
	}
	response.WriteOKResp(c, nil)
}

// 生成秩序册并返回 Excel 文件
func GenerateOrder(c *gin.Context, db *sql.DB) {
	maleData, err := db.GetRegistrationsByGender("male")
	if err != nil {
		logger.Logger.Error("Error getting male registrations: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("获取男性报名信息失败").SetCode(500))
		return
	}
	femaleData, err := db.GetRegistrationsByGender("female")
	if err != nil {
		logger.Logger.Error("Error getting female registrations: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("获取女性报名信息失败").SetCode(500))
		return
	}
	// 创建Excel文件
	f := excelize.NewFile()
	defer f.Close()

	// 设置文档属性
	f.SetDocProps(&excelize.DocProperties{
		Title: "赛事秩序册",
	})

	// 定义样式
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font:      &excelize.Font{Bold: true},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})

	// 生成男性参赛者表格
	createSheet(f, "男子组", maleData, headerStyle)
	// 生成女性参赛者表格
	createSheet(f, "女子组", femaleData, headerStyle)

	// 删除默认的Sheet1
	f.DeleteSheet("Sheet1")

	// 设置响应头
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Header("Content-Disposition", "attachment; filename=order_sheet.xlsx")
	// 将Excel文件写入响应
	if err := f.Write(c.Writer); err != nil {
		logger.Logger.Error("Error writing Excel file: ", err)
		response.WriteFailedResp(c, *response.NewFailResp().SetMsg("写入Excel文件失败").SetCode(500))
		return
	}
	response.WriteOKResp(c, nil)
}

func createSheet(f *excelize.File, sheetName string, data []sql.OrderSheetData, headerStyle int) {
	index, err := f.NewSheet(sheetName)
	if err != nil {
		logger.Logger.Error("创建Sheet失败", err)
		return
	}
	f.SetActiveSheet(index)

	// 设置列宽
	f.SetColWidth(sheetName, "A", "E", 18)

	// 设置表头
	headers := []string{"姓名", "年龄", "组别", "参赛项目", "报名时间"}
	for i, h := range headers {
		cell, _ := excelize.CoordinatesToCellName(i+1, 1)
		f.SetCellValue(sheetName, cell, h)
		f.SetCellStyle(sheetName, cell, cell, headerStyle)
	}

	// 填充数据
	for rowIdx, item := range data {
		row := rowIdx + 2 // 从第二行开始
		f.SetCellValue(sheetName, "A"+strconv.Itoa(row), item.Name)
		f.SetCellValue(sheetName, "B"+strconv.Itoa(row), item.Age)
		f.SetCellValue(sheetName, "C"+strconv.Itoa(row), item.Group)
		f.SetCellValue(sheetName, "D"+strconv.Itoa(row), item.EventName)
		f.SetCellValue(sheetName, "E"+strconv.Itoa(row),
			item.RegistrationTime.Format("2006-01-02 15:04"))
	}

	// 添加冻结窗格
	f.SetPanes(sheetName, &excelize.Panes{
		Freeze:      true,
		XSplit:      0,
		YSplit:      1,
		TopLeftCell: "A2",
		ActivePane:  "bottomRight",
	})
}
